#include "stdafx.h"
#include "player.h"
#include "baloon.h"

using namespace Ogre;



Player::Player(SceneManager *sceneMgr, OgreNewt::World *W,OgreNewt::MaterialID* stoji_m,OgreNewt::MaterialID* ide_m,OgreNewt::MaterialID* grb_mat,OgreNewt::MaterialID* flg_mat,irrklang::ISoundEngine* sEngine)
{
	tslf=0;
	slowingDown=1;
	cameraWalkFinisher=0;
	Gbody=NULL;
	soundEngine=sEngine;
	walkSoundTimer=0;
	climbTimer=0;
	fallPitch=0;
	groundID=-1;
	movespeed=10;
	crouch=0;
	crouch_am=0;
	jumpPitch=0;
	cam_walking=0;
	head_turning=0;
	mouseX=0;
	mouseY=0;
	climb_pullup=0;
	climb_move_side=0;
	climb_move_vert=0;
	pullupPos=0;
	gNormal=Vector3::ZERO;
	climbDir=Vector3::ZERO;
	climb_normal=Vector3::ZERO;
	climb_pitch=0;
	climb_yaw=0;
	gNormal.y=1;
	veee=0;
	smer=Vector3::ZERO;
	mSceneMgr=sceneMgr;
	m_World=W;
	is_climbing=0;
	vpravo=false;
	grabbed=false;
	vlavo=false;
	vpred=false;
	vzad=false;
	stoji=true;
	visi=false;
	leti=false;
	nazemi=false;
	onRope=false;
	camAngle=0;
	lastSpeed=0;
	stoji_mat=stoji_m;
	ide_mat=ide_m;
	flag_mat=flg_mat;
	grab_mat=grb_mat;
	mCamera=mSceneMgr->getCamera("Camera");
	mCamera->setPosition(0,0,0);
	mCamera->lookAt(Vector3(0,0,-1));
	Ogre::Entity* ent = mSceneMgr->createEntity( "name", "play2.mesh" );
	SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode( "CenterNode" );
	node->attachObject( ent );
    ent->setCastShadows( false );
	ent->setVisible(false);
	OgreNewt::ConvexCollisionPtr col = OgreNewt::ConvexCollisionPtr(new OgreNewt::CollisionPrimitives::ConvexHull(m_World,ent,1));
	pbody = new OgreNewt::Body( m_World, col );
	pbody->setContinuousCollisionMode(1); 
	uv= new OgreNewt::UpVector(pbody, Vector3::UNIT_Y);
	uv2= new OgreNewt::UpVector(pbody, Vector3::UNIT_Z);

	Ogre::Vector3 inertia, offset;
    col->calculateInertialMatrix(inertia, offset);
	#ifdef OGRENEWT_NO_COLLISION_SHAREDPTR
				//no longer need the collision shape object
				delete col;
	#endif
	pbody->setMassMatrix( 0.5, Vector3(20,20,20));
    pbody->setCenterOfMass(offset);
	pbody->setContinuousCollisionMode(1);
	pbody->setPositionOrientation( Ogre::Vector3(0,100,0), Ogre::Quaternion::IDENTITY );
	pbody->setLinearDamping(0.8);
	pbody->attachNode( node );
	pbody->setAutoSleep(0);
	//body->setMaterialGroupID(pmat);
	pbody->setCustomForceAndTorqueCallback<Player>(&Player::move_callback, this);


	necknode = node->createChildSceneNode( "NeckNod" );
	necknode->setPosition(Vector3(0,1,0));

	headnode = necknode->createChildSceneNode( "HeadNod" );
	headnode->setPosition(Vector3(0,0,0));

	camnode = headnode->createChildSceneNode( "CamNod" );
	camnode->attachObject(mCamera);
	camnode->setPosition(Vector3(0,0,0));

	ent = mSceneMgr->createEntity( "ent_podstava", "cone_p2.mesh" );
    col_p = OgreNewt::ConvexCollisionPtr(new OgreNewt::CollisionPrimitives::ConvexHull(m_World,ent,1));	

}

Player::~Player () {
}

void Player::move_callback(OgreNewt::Body* me, float timeStep, int threadIndex )
{
	me->addForce(Ogre::Vector3(0,-10,0));
	me->addForce(smer);
}
void Player::climb_callback(OgreNewt::Body* me, float timeStep, int threadIndex )
{
	me->setVelocity(climbDir+climb_normal*-0.5);
}
void Player::move_callback_nothing(OgreNewt::Body* me, float timeStep, int threadIndex )
{
	//me->addForce(Ogre::Vector3(0,0,0));
}
void Player::default_callback(OgreNewt::Body* me, float timeStep, int threadIndex )
{
	me->addForce(Ogre::Vector3(0,-6,0));
}
void Player::grabbed_callback(OgreNewt::Body* me, float timeStep, int threadIndex )
{
	Vector3 p;
	p=me->getOgreNode()->_getDerivedPosition();
	Vector3 p2;
	p2=necknode->_getDerivedPosition()+mCamera->getDerivedOrientation()*Vector3(0,0,-4);

	Vector3 s=(p2-p)*4;

	Vector3 o=me->getVelocity();
	Radian r=s.angleBetween(o);
	Real rad=r.valueDegrees();

		if(rad>45)
		{
		me->setVelocity(me->getVelocity()/2);
		s*=rad/40;
		}
	me->setForce(s);
	//me->setTorque(Ogre::Vector3(0,10,0));
	me->setPositionOrientation(me->getPosition(),necknode->getOrientation());
	if(s.squaredLength()>2025)
	{
	  Gbody->setMaterialGroupID(m_World->getDefaultMaterialID());
	  //Gbody->setMassMatrix(Gbody->getMass(),Gbody->getInertia()*20);
	  Gbody->setStandardForceCallback();
	  Gbody->setAngularDamping(gADT);
      Gbody->setLinearDamping(gLDT);
	  grabbed=false;
	}
}

void Player::pressedKey(const OIS::KeyEvent &arg){

switch (arg.key)
		{
			case OIS::KC_D: 
			  setVpravo(true);
			   break;
		   case OIS::KC_A: 
			  setVlavo(true);
			   break;
		   case OIS::KC_W: 
			setVpred(true);
			   break;
		   case OIS::KC_S: 
			  setVzad(true);
			   break;

		   case OIS::KC_C: 
			   setCrouch(1);
			   break;

		   case OIS::KC_V: 
			   {	
				    Ogre::Vector3 size( 0.2, 0.2,0.2 );
					Ogre::Real mass = 0.3;
					Entity* ent;
					SceneNode* node;
					Ogre::String name;

					name = "Bodyd "+Ogre::StringConverter::toString( 88 );

					ent = mSceneMgr->createEntity( name, "boxEL.mesh" );
					node = mSceneMgr->getRootSceneNode()->createChildSceneNode( name );
					node->attachObject( ent );
					node->setScale( size );
					ent->setCastShadows(true);
					ent->setMaterialName( "GreyWood" );

					OgreNewt::ConvexCollisionPtr col = OgreNewt::ConvexCollisionPtr(new OgreNewt::CollisionPrimitives::Box( m_World, size, 0 ));
					OgreNewt::Body* body = new OgreNewt::Body( m_World, col );

					Ogre::Vector3 inertia, offset;
					col->calculateInertialMatrix(inertia, offset);

					#ifdef OGRENEWT_NO_COLLISION_SHAREDPTR
						delete col;
					#endif

					body->setMassMatrix( mass, mass*inertia );
					body->setCenterOfMass(offset);
					body->attachNode( node );
					body->setType(3);
					body->setMaterialGroupID(flag_mat);
					body->setCustomForceAndTorqueCallback<Player>(&Player::climb_callback, this);
					body->setPositionOrientation( pbody->getPosition()+Vector3(0,5,0), Ogre::Quaternion::IDENTITY );
					pbody->setCustomForceAndTorqueCallback<Player>(&Player::move_callback_nothing, this);
				   climbJoint = new OgreNewt::BallAndSocket(body, pbody,  pbody->getPosition()+Vector3(0,5,0),0 ); 
			   }
			   break;

			 case OIS::KC_SPACE: 
				 skoc();
			break;
			  
           default:
              break;
		}
}
void Player::releasedKey(const OIS::KeyEvent &arg){ 

switch (arg.key)
		{
		   case OIS::KC_D: 
			   setVpravo(false);
			   break;
		   case OIS::KC_A: 
			   setVlavo(false);
			   break;
		   case OIS::KC_W: 
		       setVpred(false);
			   break;
		   case OIS::KC_S: 
			   setVzad(false);
			   break;

		   case OIS::KC_C: 
			   if(getCrouch()==1) setCrouch(2);
			   break;
			   
           default:
              break;
		}
}

void Player::pressedMouse(const OIS::MouseEvent &arg,OIS::MouseButtonID id){ 

switch (id)
        {
		case OIS::MB_Right:	
		  if (!grabbed)
		  tryToGrab();

            break;
        }
}
void Player::releasedMouse(const OIS::MouseEvent &arg, OIS::MouseButtonID id){ 

	switch (id)
        {
		case OIS::MB_Right:
			  if (grabbed){
				  Gbody->setMaterialGroupID(m_World->getDefaultMaterialID());
				  //Gbody->setMassMatrix(Gbody->getMass(),Gbody->getInertia()*20);
				  Gbody->setCustomForceAndTorqueCallback<Player>(&Player::default_callback, this);
				  Gbody->setAngularDamping(gADT);
			      Gbody->setLinearDamping(gLDT);
				  pbody->setMassMatrix(pbody->getMass()-Gbody->getMass(),pbody->getInertia());
				  grabbed=false;
			  }
            break;
        }
}
void Player::movedMouse(const OIS::MouseEvent &e){
mouseX=-1*e.state.X.rel;
mouseY=-1*e.state.Y.rel;
rotateCamera(e.state.X.rel,e.state.Y.rel);
}


void Player::setCrouch(char b)
{ 
	if(visi) 
	{
		delete climbJoint; 
		visi=false;
		climbTimer=1;
	}
	else 
	if(is_climbing) 
	{	
		stopClimbing();
	}
	else
	crouch=b;
}

void Player::walkingSound(Ogre::Real time)
{
walkSoundTimer+=(time*pbody->getVelocity().length()/6.6);

if(walkSoundTimer>0.4){
Vector3 ppos=pbody->getPosition();
Ogre::Real rand=Ogre::Math::RangeRandom(0,5);
irrklang::ISound* music;

switch (groundID)
{

case 1:
if(rand<1.7)
music = soundEngine->play3D("../../media/Stone_Hard_Walk_01.wav",irrklang::vec3df(ppos.x,ppos.y-2,ppos.z), false, false, true, irrklang::ESM_AUTO_DETECT, true);
else if(rand<3.4)
music = soundEngine->play3D("../../media/Stone_Hard_Walk_02.wav",irrklang::vec3df(ppos.x,ppos.y-2,ppos.z), false, false, true, irrklang::ESM_AUTO_DETECT, true);
else
music = soundEngine->play3D("../../media/Stone_Hard_Walk_03.wav",irrklang::vec3df(ppos.x,ppos.y-2,ppos.z), false, false, true, irrklang::ESM_AUTO_DETECT, true);
music->setMaxDistance(10);
break;
case 0:
case 2:
if(rand<1)
music = soundEngine->play3D("../../media/grass_walk_01.wav",irrklang::vec3df(ppos.x,ppos.y-2,ppos.z), false, false, true, irrklang::ESM_AUTO_DETECT, true);
else if(rand<2)
music = soundEngine->play3D("../../media/grass_walk_02.wav",irrklang::vec3df(ppos.x,ppos.y-2,ppos.z), false, false, true, irrklang::ESM_AUTO_DETECT, true);
else if(rand<3)
music = soundEngine->play3D("../../media/Grass_Walk_03.wav",irrklang::vec3df(ppos.x,ppos.y-2,ppos.z), false, false, true, irrklang::ESM_AUTO_DETECT, true);
else if(rand<4)
music = soundEngine->play3D("../../media/dirt_walk_02.wav",irrklang::vec3df(ppos.x,ppos.y-2,ppos.z), false, false, true, irrklang::ESM_AUTO_DETECT, true);
else
music = soundEngine->play3D("../../media/Dirt_Walk_03.wav",irrklang::vec3df(ppos.x,ppos.y-2,ppos.z), false, false, true, irrklang::ESM_AUTO_DETECT, true);
music->setMaxDistance(10);
break;
case 3:
if(rand<1.25)
music = soundEngine->play3D("../../media/metalgrate1.wav",irrklang::vec3df(ppos.x,ppos.y-2,ppos.z), false, false, true, irrklang::ESM_AUTO_DETECT, true);
else if(rand<2.5)
music = soundEngine->play3D("../../media/metalgrate2.wav",irrklang::vec3df(ppos.x,ppos.y-2,ppos.z), false, false, true, irrklang::ESM_AUTO_DETECT, true);
else if(rand<3.75)
music = soundEngine->play3D("../../media/metalgrate3.wav",irrklang::vec3df(ppos.x,ppos.y-2,ppos.z), false, false, true, irrklang::ESM_AUTO_DETECT, true);
else
music = soundEngine->play3D("../../media/metalgrate4.wav",irrklang::vec3df(ppos.x,ppos.y-2,ppos.z), false, false, true, irrklang::ESM_AUTO_DETECT, true);
music->setMaxDistance(10);
break;
}


music->getSoundEffectControl()->enableWavesReverbSoundEffect(0,-15,2600,0.5);
walkSoundTimer=0;}
}

void Player::skoc()
{
	if(onRope)
	{
	delete climbJoint;
	onRope=false;
	climbTimer=0.35;

	jumpPitchsize=0;
	jumpPitch=1;
	Vector3 vel=pbody->getVelocity();	pbody->setVelocity(vel+Vector3(0,9,0));
	}
	else
	if(visi)
	{
	delete climbJoint;
	pbody->setVelocity(pbody->getVelocity()+Vector3(0,10,0));
	visi=false;
	if(leti)
	{pbody->setCustomForceAndTorqueCallback<Player>(&Player::move_callback, this); leti=false;}
	climbTimer=0.5;
	}
	else
	if(is_climbing==2 || is_climbing==6)
	{
	Vector3 pos=pbody->getPosition();
	irrklang::ISound* music = soundEngine->play3D("../../media/pullup.wav",irrklang::vec3df(pos.x,pos.y+2,pos.z), false, false, true, irrklang::ESM_AUTO_DETECT, false);
	music->setMaxDistance(5);
	music->setPlaybackSpeed(0.8);
	music->setVolume(0.7);
	climb_pullup=0.05;

	}
	else
	//if(nazemi)
	{
	//Vector3 ppos=pbody->getPosition();
	//irrklang::ISound* music;
	//music = soundEngine->play3D("../../media/dych.wav",irrklang::vec3df(ppos.x,ppos.y,ppos.z), false, false, true, irrklang::ESM_AUTO_DETECT, false);
//	music->setMaxDistance(10);
	jumpPitchsize=0;
	jumpPitch=1;
	Vector3 vel=pbody->getVelocity();	pbody->setVelocity(vel+Vector3(0,9,0));
	}
}
void Player::manageFall()
{
	veee=abs(lastSpeed.length())*2;
	fallPitchsize=0;
	//necknode->pitch(Degree(-veee/3), Node::TS_LOCAL);
	fallPitch=1;
	Vector3 ppos=pbody->getPosition();
	irrklang::ISound* music;
	
	if(veee>35)
	{
	veee=80;
	*postPr1=6;
	slowingDown=0;
	irrklang::ISound* music2;
	music2 = soundEngine->play3D("../../media/pad.wav",irrklang::vec3df(ppos.x,ppos.y,ppos.z), false, false, true, irrklang::ESM_AUTO_DETECT, false);
	music2->setMaxDistance(10);
	/*delete uv;
	delete uv2;
	pbody->setLinearDamping(2);
	pbody->setAngularDamping(Ogre::Vector3(2));
	pbody->setMassMatrix(5,Ogre::Vector3(1,1,1));
	pbody->setOmega(Ogre::Vector3(3,0,0));*/
	}
	
	switch (groundID)
	{
	case 1:
	music = soundEngine->play3D("../../media/Stone_Hard_Walk_02.wav",irrklang::vec3df(ppos.x,ppos.y-2,ppos.z), false, false, true, irrklang::ESM_AUTO_DETECT, false);
	music->setMaxDistance(10);
	break;
	case 0:
	case 2:
	music = soundEngine->play3D("../../media/grass_run_02.wav",irrklang::vec3df(ppos.x,ppos.y-2,ppos.z), false, false, true, irrklang::ESM_AUTO_DETECT, false);
	music->setMaxDistance(10);
	break;
	case 3:
	music = soundEngine->play3D("../../media/metalgrate1.wav",irrklang::vec3df(ppos.x,ppos.y-2,ppos.z), false, false, true, irrklang::ESM_AUTO_DETECT, false);
	music->setMaxDistance(10);
	break;
	
	}
	
}

void Player::rotateCamera(Real hybX,Real hybY)
{
		hybY*=-0.1;
		camAngle+=(hybY);
		if (camAngle>-80 && camAngle<80)
			necknode->pitch(Degree(hybY), Node::TS_LOCAL);
		else { camAngle=camAngle-hybY; 
			if (camAngle<0) {necknode->pitch(Degree(-80-camAngle), Node::TS_LOCAL); camAngle=-80.0;} 
			if (camAngle>0) {necknode->pitch(Degree(80-camAngle), Node::TS_LOCAL); camAngle=80.0;} 
			  } 

		if(!(visi || is_climbing) )
		{
			necknode->yaw(Degree(-0.1 * hybX), Node::TS_WORLD);
		}
		else
		{
			Vector3 pohlad=mCamera->getDerivedOrientation()*Vector3(0,0,-1); 
			pohlad.y=0; 
			pohlad.normalise();
			Real angle=climb_normal.angleBetween(pohlad).valueDegrees();

			Real climbCam= climb_normal.getRotationTo(pohlad).getYaw().valueDegrees();

			if((climbCam>0 && hybX<0) || (climbCam<0 && hybX>0))
			{
			necknode->yaw(Degree(-0.1 * hybX), Node::TS_WORLD);
			}
			else
			{
			Real max_angle=90;
			if(is_climbing) max_angle=120;

			Real spomal;
			angle-=(180-max_angle);
			if(angle<0) spomal=0;
			else spomal=angle/max_angle;
			necknode->yaw(Degree(-0.1 * hybX* spomal), Node::TS_WORLD);
			}

		}

}

void Player::updateHead(Real time)
{

	if(!stoji && nazemi) 
	{
	if (movespeed<17) movespeed+=time*10;
	if (movespeed>17) movespeed=17;
	walkingSound(time);
	}
	else movespeed=7;

	if (climbTimer>0) {climbTimer-=time;}


	if(crouch>0)
	{
		if(crouch==1)
		{
		if(crouch_am>-1.5) crouch_am-=time*8;
		if(crouch_am<-1.5) crouch_am=-1.5;
			necknode->setPosition(0,1+crouch_am,0);
		}
		if(crouch==2)
		{	
		crouch_am+=time*8;
		if(crouch_am>0) {crouch_am=0; crouch=0;}
			necknode->setPosition(0,1+crouch_am,0);
		}

		if(fallPitch==1)
		{fallPitchsize+=time; necknode->pitch(Degree(veee*time*-3), Node::TS_LOCAL); if(fallPitchsize>0.1) fallPitch=2;}
		else if(fallPitch==2)
		{fallPitchsize-=time; necknode->pitch(Degree(veee*time*1.5), Node::TS_LOCAL); if(fallPitchsize<=0) {necknode->pitch(Degree(veee*(fallPitchsize+time)*1.5), Node::TS_LOCAL); fallPitch=0;}}
		if(jumpPitch==1)
		{jumpPitchsize+=time; necknode->pitch(Degree(time*-10), Node::TS_LOCAL); if(jumpPitchsize>0.1) jumpPitch=2;}
		else if(jumpPitch==2)
		{jumpPitchsize-=time; necknode->pitch(Degree(time*5), Node::TS_LOCAL); if(jumpPitchsize<=0) {jumpPitch=0; necknode->pitch(Degree((jumpPitchsize+time)*5), Node::TS_LOCAL);}}
	}

	else
	//not crouching
	{

	if(fallPitch==1)
	{
		fallPitchsize+=time;
		if(fallPitchsize>=0.1) {fallPitch=2; necknode->pitch(Degree(veee*(0.1-fallPitchsize+time)*-3), Node::TS_LOCAL); 
		fallPitchsize=0.2; }
		else
		{necknode->pitch(Degree(veee*time*-3), Node::TS_LOCAL); 
		}
	}
	else if(fallPitch==2)
	{
		fallPitchsize-=time;
		if(fallPitchsize<=0) { fallPitch=0; necknode->pitch(Degree(veee*(fallPitchsize+time)*1.5), Node::TS_LOCAL); 
		}
		else
		{necknode->pitch(Degree(veee*time*1.5), Node::TS_LOCAL); 
		}
	}

	if(jumpPitch==1)
	{
		jumpPitch=0;
		
	}
	else if(jumpPitch==2)
	{
		jumpPitchsize-=time; 
		
	}


	//walking camera
	if(!is_climbing && !stoji && nazemi && (pbody->getVelocity().length()>2))
	{
	cameraWalkFinisher=1;
	cam_walking+=time*pbody->getVelocity().length();
	camnode->setPosition(0,-1*abs(Ogre::Math::Sin(cam_walking))/10,0);
	camnode->roll(Degree(Ogre::Math::Sin(cam_walking+Ogre::Math::PI/2))*time*5);
	}
	else if (cameraWalkFinisher)
	{
		if(nazemi) cam_walking+=time*8; else cam_walking+=time*10;
		Real value=Ogre::Math::Sin(cam_walking);

		if(cameraWalkFinisher==1)
		{
		if(value>0) cameraWalkFinisher=2;		
		else cameraWalkFinisher=3;
		}


		if ((value>0 && cameraWalkFinisher==3) || (value<0 && cameraWalkFinisher==2))
		{
			camnode->setPosition(0,0,0);
			necknode->setPosition(0,1,0);
			camnode->resetOrientation();
			cameraWalkFinisher=0;
		}
		else
		{
			camnode->setPosition(0,-1*abs(value)/10,0);
			camnode->roll(Degree(Ogre::Math::Sin(cam_walking+Ogre::Math::PI/2))*time*5);
		}
	}

	//roll camera a bit while turning
	if(nazemi && vpred && abs(mouseX)>5)
	{
		head_turning+=(pbody->getVelocity().length()/9)*(mouseX-5)/250.0f;
		if(head_turning>8)head_turning=8;
		if(head_turning<-8)head_turning=-8;
		headnode->setOrientation(Quaternion(Ogre::Radian(head_turning/60),Vector3(0,0,1)));
	}
	else
	if(head_turning>0)
	{
		head_turning-=time*30;
		if(head_turning<0) head_turning=0;
		headnode->setOrientation(Quaternion(Ogre::Radian(head_turning/60),Vector3(0,0,1)));
	}
	else
	if(head_turning<0)
	{
		head_turning+=time*30;
		if(head_turning>0) head_turning=0;
		headnode->setOrientation(Quaternion(Ogre::Radian(head_turning/60),Vector3(0,0,1)));
	}


	mouseX=0;
	mouseY=0;

	}

}

void Player::update(Real time)
{

		updateStats();

		tslf=time;


		if(slowingDown<1)
		{slowingDown+=(tslf/2);
		if(slowingDown>1) slowingDown=1;}


		smer=Vector3::ZERO;

		if(!is_climbing)
		if (!vpravo && !vpred && !vzad && !vlavo) {pbody->setMaterialGroupID(stoji_mat); stoji=true; walkSoundTimer=0.37; }else
		{
		pbody->setMaterialGroupID(ide_mat); stoji=false; 
		if (!vlavo && !vpravo) {
			if (vpred){smer=mCamera->getDerivedOrientation()*Vector3(0,0,-1); smer.y=0; smer.normalise();}
		if (vzad) {smer=mCamera->getDerivedOrientation()*Vector3(0,0,1); smer.y=0; smer.normalise();}} else  
		{
			if (vpravo){
				if (!vpred && !vzad) {smer=mCamera->getDerivedOrientation()*Vector3(1,0,0); smer.y=0; smer.normalise();} else
				if (vpred) {smer=mCamera->getDerivedOrientation()*Vector3(1,0,-1); smer.y=0; smer.normalise();} else
				if (vzad) {smer=mCamera->getDerivedOrientation()*Vector3(1,0,1); smer.y=0; smer.normalise();} 
				}

			if (vlavo){
				if (!vpred && !vzad) {smer=mCamera->getDerivedOrientation()*Vector3(-1,0,0); smer.y=0; smer.normalise();} else
				if (vpred) {smer=mCamera->getDerivedOrientation()*Vector3(-1,0,-1); smer.y=0; smer.normalise();} else
				if (vzad) {smer=mCamera->getDerivedOrientation()*Vector3(-1,0,1); smer.y=0; smer.normalise();} 
			}
		}  
		
		if (nazemi) 
		{
			Vector3 look=mCamera->getDerivedOrientation()*Vector3(0,0,-1); 
			look.y=0; 
			Vector3 vel=pbody->getVelocity();
			vel.y=0;

			if(gNormal.y>0.8)
				smer+=(1-gNormal.y)*smer*2;

			Real rad=look.angleBetween(vel).valueDegrees();

			if(rad>45 && vpred && !vzad && !vpravo && !vlavo)
				smer*=movespeed*rad/30;
			else 
			{
				Real ebd=1.0f;
				Real l=pbody->getVelocity().length();
				if(l>9)
				{
					ebd=1/(l-8);
				}
				smer*=movespeed*ebd*slowingDown;
			}

			if(gNormal.y>0.7)
			{
				Vector3 antiSlide=-gNormal;
				antiSlide.y*=-1;
				smer+=antiSlide*20*(1-gNormal.y);
			}

			if(crouch>0) smer/=3;
		}

		else smer*=2;
		}

		if(is_climbing)
		{


			if (!vpravo && !vpred && !vzad && !vlavo && !climb_move_side && !climb_move_vert && !climb_pullup) 
			{pbody->setMaterialGroupID(stoji_mat); stoji=true;}
			else
			stoji=false; 

			//making pullup
			if(climb_pullup)
			{
				pbody->setMaterialGroupID(ide_mat);

				if(climb_pullup>0)
				{
					
					climb_pullup+=2.5*tslf;
					if(climb_pullup>2.5) climb_pullup=2.5;
					climbDir=-climb_normal;
					//climbDir.y=0;
					//climbDir.normalise();
					
					Real v=1/climb_pullup;
					climbDir*=climb_pullup;
					climbDir.y=v*2;

					if(climb_pullup==2.5) { climb_pullup=0; stopClimbing(); climbTimer=0;}
				}
				else
				{
					climb_pullup+=2*tslf;
					if(climb_pullup>=0) climb_pullup=0;

					Vector3 pos=pbody->getPosition();
					pos.y=pullupPos-1.25;
					pbody->setPositionOrientation(pos,pbody->getOrientation());
				}
			}
			else
			//already on move to side
			if(climb_move_side)
			{
				pbody->setMaterialGroupID(ide_mat);

				Vector3 dir=pbody->getVelocity();
				dir.y=0;
				pbody->setVelocity(dir);

				//right
				if(climb_move_side>0)
				{
					if(canClimb(1))
					{
					climbDir=climb_normal;
					climbDir.y=0;
					climbDir.normalise();
					Real temp(climbDir.x);
					climbDir.x=2*climbDir.z;
					climbDir.z=-2*temp;
					}
					else
					{
					climbDir=Ogre::Vector3::ZERO;
					pbody->setMaterialGroupID(stoji_mat);
					}

					climb_move_side-=tslf*3;
					if(climb_move_side<=0) {climb_move_side=0; pbody->setMaterialGroupID(stoji_mat);}
					camnode->setPosition((1-abs(climb_move_side-1))/2,0,0);
					headnode->setOrientation(Quaternion(Ogre::Radian((1-abs(climb_move_side-1))/20),Vector3(1,0,0)));
				}
				else
				//left
				if(climb_move_side<0)
				{
					if(canClimb(0))
					{
					climbDir=climb_normal;
					climbDir.y=0;
					climbDir.normalise();
					Real temp(climbDir.x);
					climbDir.x=-2*climbDir.z;
					climbDir.z=2*temp;	
					}
					else
					{
					climbDir=Ogre::Vector3::ZERO;
					pbody->setMaterialGroupID(stoji_mat);
					}

					climb_move_side+=tslf*3;
					if(climb_move_side>=0) {climb_move_side=0; pbody->setMaterialGroupID(stoji_mat);}
					camnode->setPosition((abs(climb_move_side+1)-1)/2,0,0);
					headnode->setOrientation(Quaternion(Ogre::Radian((1-abs(-climb_move_side-1))/20),Vector3(1,0,0)));
				}
			}
			else	
			//already on move vertically
			if(climb_move_vert)
			{
				pbody->setMaterialGroupID(ide_mat);
				Vector3 dir=pbody->getVelocity();
				dir.x=0;
				dir.z=0;
				pbody->setVelocity(dir);

				if(climbDir.y>0)
				{
					if(!canClimb(2))
					{
						climbDir=Vector3::ZERO;
						pbody->setMaterialGroupID(stoji_mat);
					}
				}
				else
				{
					if(!canClimb(3))
					{
						climbDir=Vector3::ZERO;
						pbody->setMaterialGroupID(stoji_mat);
					}
				}

				//right phase
				if(climb_move_vert>0)
				{
					climb_move_vert-=tslf*4;
					if(climb_move_vert<=0) 
					{
						if(vpred)
						{
						Vector3 pohlad=mCamera->getDerivedOrientation()*Vector3(0,0,-1);	
						bool con=false;
						if(pohlad.y>0) { if(canClimb(2)) {climbDir=Vector3(0,1.5,0); pbody->setMaterialGroupID(ide_mat); con=true;}} 
						else { if(canClimb(3)) {climbDir=Vector3(0,-1.5,0); pbody->setMaterialGroupID(ide_mat); con=true;}} 
						if(con){
						climb_move_vert=-2-climb_move_vert;
						camnode->setOrientation(Quaternion(Ogre::Radian((abs(climb_move_vert+1)-1)/20),Vector3(-0.5,0,1)));}
						else pbody->setMaterialGroupID(stoji_mat);
						}
						else
						{
						climb_move_vert=0;
						camnode->setOrientation(Quaternion(Ogre::Radian((1-abs(climb_move_vert-1))/20),Vector3(0.5,0,1)));
						pbody->setMaterialGroupID(stoji_mat);
						}
					}
					else
					camnode->setOrientation(Quaternion(Ogre::Radian((1-abs(climb_move_vert-1))/20),Vector3(-0.5,0,1)));
				}
				else
				//left phase
				if(climb_move_vert<0)
				{
					climb_move_vert+=tslf*4;
					if(climb_move_vert>=0) 
					{
						if(vpred)
						{
						Vector3 pohlad=mCamera->getDerivedOrientation()*Vector3(0,0,-1);	
						bool con=false;
						if(pohlad.y>0) { if(canClimb(2)) {climbDir=Vector3(0,1.5,0); pbody->setMaterialGroupID(ide_mat); con=true;}} 
						else { if(canClimb(3)) {climbDir=Vector3(0,-1.5,0); pbody->setMaterialGroupID(ide_mat); con=true;}} 
						if(con){
						climb_move_vert=2-climb_move_vert;
						camnode->setOrientation(Quaternion(Ogre::Radian((1-abs(climb_move_vert-1))/20),Vector3(0.5,0,1)));}
						else pbody->setMaterialGroupID(stoji_mat);
						}
						else
						{
						camnode->setOrientation(Quaternion(Ogre::Radian((abs(climb_move_vert+1)-1)/20),Vector3(-0.5,0,1)));
						climb_move_vert=0;
						pbody->setMaterialGroupID(stoji_mat);
						}
					}
					else
					camnode->setOrientation(Quaternion(Ogre::Radian((abs(climb_move_vert+1)-1)/20),Vector3(0.5,0,1)));
				}
			}
			else
			//not moving yet
			{
				if(vpred)
				{
					Vector3 pohlad=mCamera->getDerivedOrientation()*Vector3(0,0,-1);			

					if(pohlad.y>0)
					{
						if(canClimb(2))
						{
						climbDir=Vector3(0,2,0);
						climb_move_vert=2;
						pbody->setMaterialGroupID(ide_mat);
						}
						else
						pbody->setMaterialGroupID(stoji_mat);
					}
					else
					{
						if(canClimb(3))
						{
						climbDir=Vector3(0,-2,0);
						climb_move_vert=-2;
						pbody->setMaterialGroupID(ide_mat);
						}
						else
						pbody->setMaterialGroupID(stoji_mat);
					}				
				}
				else
				if(vlavo)
				{
					if(canClimb(0))
					{
					pbody->setMaterialGroupID(ide_mat);
					climbDir=climb_normal;
					climbDir.y=0;
					climbDir.normalise();
					Real temp(climbDir.x);
					climbDir.x=-2*climbDir.z;
					climbDir.z=2*temp;

					Vector3 movement=pbody->getVelocity();
					movement.y=0;

					if(!climb_move_side && movement.length()>0.1)
						climb_move_side=-2;
					}
					else
					pbody->setMaterialGroupID(stoji_mat);
				}
				else
				if(vpravo)
				{
					if(canClimb(1))
					{
					pbody->setMaterialGroupID(ide_mat);
					climbDir=climb_normal;
					climbDir.y=0;
					climbDir.normalise();
					Real temp(climbDir.x);
					climbDir.x=2*climbDir.z;
					climbDir.z=-2*temp;

					Vector3 movement=pbody->getVelocity();
					movement.y=0;

					if(!climb_move_side && movement.length()>0.1)
						climb_move_side=2;
					}
					else
					pbody->setMaterialGroupID(stoji_mat);

				}
				else
				climbDir=Vector3::ZERO;
			}

			//turning sides
			if(climb_yaw)
			{
				

				if(climb_yaw<0)
					{
					if((climb_yaw+tslf)>=0)
					{necknode->yaw(Ogre::Radian(climb_yaw), Node::TS_WORLD); climb_yaw=0;}
					else
					{necknode->yaw(Ogre::Radian(-tslf), Node::TS_WORLD); climb_yaw+=tslf;
					}
					}
				else
					{
					if((climb_yaw-tslf)<=0)
					{necknode->yaw(Ogre::Radian(climb_yaw), Node::TS_WORLD); climb_yaw=0;}
					else
					{necknode->yaw(Ogre::Radian(tslf), Node::TS_WORLD); climb_yaw-=tslf;
					}
					}

			}
			/*if(climb_pitch)
			{
				if(climb_pitch<0)
					{
					if((climb_pitch+tslf)>=0)
					{necknode->pitch(Ogre::Radian(climb_pitch), Node::TS_WORLD); climb_pitch=0;}
					else
					{necknode->pitch(Ogre::Radian(-tslf), Node::TS_WORLD); climb_pitch+=tslf;}
					}
				else
					{
					if((climb_pitch-tslf)<=0)
					{necknode->pitch(Ogre::Radian(climb_pitch), Node::TS_WORLD); climb_pitch=0;}
					else
					{necknode->pitch(Ogre::Radian(tslf), Node::TS_WORLD); climb_pitch-=tslf;}
					}
			}*/
		}


		updateHead(time);

}



void Player::updateStats()
{

   float interpolationFactor = mPreviousFPS*0.03f;
 

   Ogre::Quaternion estimatedOrientation = Ogre::Quaternion::Slerp(interpolationFactor,camnode->_getDerivedOrientation(),prevOr);
   Ogre::Vector3    estimatedPosition    = (1-interpolationFactor)*camnode->_getDerivedPosition()+interpolationFactor*prevPos;
   Ogre::Matrix4 viewMatrix =Ogre::Math::makeViewMatrix(estimatedPosition,estimatedOrientation);
   Ogre::Matrix4 projectionMatrix   = mCamera->getProjectionMatrix();
   *pVP       = projectionMatrix*viewMatrix;
   if(prevOr.equals(camnode->_getDerivedOrientation(),Ogre::Radian(0.01)) && prevPos==camnode->_getDerivedPosition())
	   *pVP = projectionMatrix*mCamera->getViewMatrix();
	*iVP=(mCamera->getProjectionMatrix()*mCamera->getViewMatrix()).inverse();


    mPreviousFPS=1/tslf;
	prevPos=camnode->_getDerivedPosition();
	prevOr=camnode->_getDerivedOrientation();






		Vector3 p=pbody->getPosition();

		OgreNewt::BasicRaycast ray( m_World,(p-Vector3(0,1.6,0)),(p-Vector3(0,2.6,0))  ,true);
		OgreNewt::BasicRaycast::BasicRaycastInfo info = ray.getInfoAt(0);
			
			if (info.mBody)
			{
				gNormal=info.mNormal;
			}

			if (info.mBody && info.mBody->getPosition().y>=(p.y-2.3))
			{
				Ogre::Any any = info.mBody->getUserData();
				if(!any.isEmpty())
			    groundID=any_cast<int>(any);
				else
				groundID=0;

				if(!nazemi) manageFall();
				nazemi=true;
				pbody->setLinearDamping(4);

			} else { 
			
		OgreNewt::BasicConvexcast rayc( m_World,col_p,(p-Vector3(0,2,0)),Ogre::Quaternion::IDENTITY,(p-Vector3(0,2.5,0)),1,1);
		OgreNewt::BasicConvexcast::ConvexcastContactInfo infoc = rayc.getInfoAt(0);
		if (infoc.mBody)
			{	
				Ogre::Any any = infoc.mBody->getUserData();
				if(!any.isEmpty())
			    groundID=any_cast<int>(any);
				else
				groundID=0;
	
				if(!nazemi){ manageFall();}
				nazemi=true;
				if (!info.mBody) gNormal=1;
				pbody->setLinearDamping(4);

			} 
			 else 
			{
				groundID=-1;
				lastSpeed=pbody->getVelocity();
				nazemi=false; 
				pbody->setLinearDamping(0.0); 
				gNormal=0;
		     } 
			}
		

		p=necknode->_getDerivedPosition();
		Vector3 predsebou=mCamera->getDerivedOrientation()*Vector3(0,0,-1);
		predsebou.y=0; 
		predsebou.normalise();
		predsebou*=2;


		
		ray = OgreNewt::BasicRaycast( m_World,(p+Vector3(0,0.25,0)),(predsebou+p+Vector3(0,0.25,0))  ,true);
		info = ray.getInfoAt(0);
			if (info.mBody)
			{
				if(!visi && climbTimer<=0)
				{
					if(info.mBody->getType()==4)
					{
					Ogre::Any any = info.mBody->getOgreNode()->getUserAny();
					any_cast<Baloon*>(any)->setTracker(track);
					climbJoint = new OgreNewt::BallAndSocket(info.mBody, pbody, p,0 ); 
					visi=true; 
					leti=true;
					pbody->setCustomForceAndTorqueCallback<Player>(&Player::move_callback_nothing, this);
					}	
				}

				if(info.mBody->getType()==7 && !onRope && climbTimer<=0.25)
				{
					climbJoint = new OgreNewt::BallAndSocket(info.mBody, pbody, p ,0); 
					onRope=true; 
				}
			}

		
		if(!onRope && !nazemi && !visi && !is_climbing && climbTimer<=0)
		{
			ray = OgreNewt::BasicRaycast( m_World,p+Vector3(0,0.25,0),p+Vector3(0,0.25,0)+predsebou/1.5 ,true);
			info = ray.getInfoAt(0);
				if (info.mBody)
				{
					if (info.mBody->getType()==5 || info.mBody->getType()==2 || info.mBody->getType()==6)
					{	
						climb_normal=info.mNormal;
						climb_normal.normalise();
						startClimbing(info.mBody->getType());

						if(info.mBody->getType()==2) 
						{
							pullupPos=info.getBody()->getPosition().y-0.15;
							Vector3 pos=pbody->getPosition();
							pos.y=pullupPos-1.25;
							pbody->setPositionOrientation(pos,pbody->getOrientation());
							climbDir=Vector3::ZERO;

							climb_pullup=pbody->getPosition().y+0.25-pullupPos;
							if(climb_pullup>0) climb_pullup=0;
						}
						
					}
				}

		}
		else
		if(is_climbing)
		{
			ray = OgreNewt::BasicRaycast( m_World,p+Vector3(0,0.25,0),p+Vector3(0,0.25,0)+climb_normal*-3 ,true);
			info = ray.getInfoAt(0);
				if (info.mBody)
				{
					if ((info.mBody->getType()==5 || info.mBody->getType()==2 || info.mBody->getType()==6)&& !nazemi)
					{	
						is_climbing=info.mBody->getType();
						Ogre::Vector3 c_normal=info.mNormal;
						c_normal.normalise();
						if(c_normal!=climb_normal)
						{
							Quaternion angles=c_normal.getRotationTo(climb_normal);
							//if(!climb_yaw) climb_yaw=-angles.getYaw().valueRadians();
							climb_pitch=angles.getPitch().valueRadians();
						}
						climb_normal=c_normal;
					}
					else
					{
						if(!climb_pullup)
						stopClimbing();
					}
				}
		}

}

void Player::startClimbing(char type)
{
   Ogre::Vector3 size( 0.2, 0.2,0.2 );
	Ogre::Real mass = 0.3;
	Entity* ent;
	SceneNode* node;
	Ogre::String name("BodyChytac");

	ent = mSceneMgr->createEntity( name, "boxEL.mesh" );
	node = mSceneMgr->getRootSceneNode()->createChildSceneNode( name );
	node->attachObject( ent );
	node->setScale( size );
	ent->setCastShadows(true);
	ent->setMaterialName( "GreyWood" );

	OgreNewt::ConvexCollisionPtr col = OgreNewt::ConvexCollisionPtr(new OgreNewt::CollisionPrimitives::Box( m_World, size, 0 ));
	OgreNewt::Body* body = new OgreNewt::Body( m_World, col );

	Ogre::Vector3 inertia, offset;
	col->calculateInertialMatrix(inertia, offset);

	#ifdef OGRENEWT_NO_COLLISION_SHAREDPTR
		delete col;
	#endif

	body->setMassMatrix( mass, mass*inertia );
	body->setCenterOfMass(offset);
	body->attachNode( node );
	body->setMaterialGroupID(flag_mat);
	body->setCustomForceAndTorqueCallback<Player>(&Player::climb_callback, this);
	body->setPositionOrientation( pbody->getPosition()+Vector3(0,5,0), Ogre::Quaternion::IDENTITY );
	pbody->setCustomForceAndTorqueCallback<Player>(&Player::move_callback_nothing, this);
	climbJoint = new OgreNewt::BallAndSocket(body, pbody,  pbody->getPosition()+Vector3(0,5,0) ,0);
	pbody->setMaterialGroupID(stoji_mat);

	is_climbing=type;
}

void Player::stopClimbing()
{
	pbody->setCustomForceAndTorqueCallback<Player>(&Player::move_callback, this);
	OgreNewt::Body* b=climbJoint->getBody0();
	delete climbJoint; 
	delete b;
	mSceneMgr->destroyEntity("BodyChytac");
	mSceneMgr->destroySceneNode("BodyChytac");
	is_climbing=0;
	climbTimer=1;
	climb_pitch=0;
	climb_yaw=0;
}

void Player::tryToGrab()
{
		Vector3 p=necknode->_getDerivedPosition();
		OgreNewt::BasicRaycast ray(m_World,p,p+mCamera->getDerivedOrientation()*Vector3(0,0,-5)  ,true);
		OgreNewt::BasicRaycast::BasicRaycastInfo info = ray.getInfoAt(0);

			if (info.mBody)
			{
				if (info.mBody->getType()==3)
				{									
				Gbody=info.mBody;
				Gbody->setMaterialGroupID(grab_mat);
				Gbody->unFreeze();
				Gbody->setCustomForceAndTorqueCallback<Player>(&Player::grabbed_callback, this);
				//Gbody->setMassMatrix(Gbody->getMass(),Gbody->getInertia()/20);
				gADT=Gbody->getAngularDamping();
				gLDT=Gbody->getLinearDamping();
				pbody->setMassMatrix(pbody->getMass()+Gbody->getMass(),pbody->getInertia());
				Gbody->setAngularDamping(Vector3(1,1,1)*300);
				Gbody->setLinearDamping(300);
				grabbed=true;
				}
			}
}

bool Player::canClimb(char smer)
{
		Vector3 off=climb_normal;

		//0-left,1-right,2-up,3-down
		switch(smer)
		{
		case 0: 
			{Real temp(off.x);
			off.x=-off.z;
			off.z=temp;
			break;}
		case 1: 
			{Real temp(off.x);
			off.x=off.z;
			off.z=-temp;
			break;}
		case 2: 
			{off.y=0;
			off.y=off.length();
			off.x=0;
			off.z=0;
			break;}
		case 3: 
			{off.y=0;
			off.y=-off.length();
			off.x=0;
			off.z=0;
			break;}
		};


		Vector3 p=necknode->_getDerivedPosition()+off/3;
		Ogre::LogManager::getSingleton().getDefaultLog()->logMessage(Ogre::StringConverter::toString(smer),Ogre::LML_NORMAL);
		Ogre::LogManager::getSingleton().getDefaultLog()->logMessage(Ogre::StringConverter::toString(off),Ogre::LML_NORMAL);
		Ogre::LogManager::getSingleton().getDefaultLog()->logMessage(Ogre::StringConverter::toString(climb_normal),Ogre::LML_NORMAL);
		OgreNewt::BasicRaycast ray(m_World,p+Vector3(0,0.25,0),p+Vector3(0,0.25,0)+climb_normal*-3 ,true);
		OgreNewt::BasicRaycast::BasicRaycastInfo info = ray.getInfoAt(0);

				if (info.mBody && (info.mBody->getType()==6 || info.mBody->getType()==5 || info.mBody->getType()==2))
				{
					Ogre::LogManager::getSingleton().getDefaultLog()->logMessage("Y",Ogre::LML_NORMAL);
					return true;	
				}
				else
				{	
							p=necknode->_getDerivedPosition();
							OgreNewt::BasicRaycast ray2(m_World,p+Vector3(0,0.25,0),p+Vector3(0,0.25,0)+climb_normal*-3 ,true);
							OgreNewt::BasicRaycast::BasicRaycastInfo info2 = ray2.getInfoAt(0);

							if (info2.mBody && (info2.mBody->getType()==6 || info2.mBody->getType()==5 || info2.mBody->getType()==2))
							{
								p=necknode->_getDerivedPosition()+off;
								OgreNewt::BasicRaycast ray3(m_World,p+Vector3(0,0.25,0),p+Vector3(0,0.25,0)+climb_normal*-3 ,true);
								OgreNewt::BasicRaycast::BasicRaycastInfo info3 = ray3.getInfoAt(0);

								if (info3.mBody && (info3.mBody->getType()==6 || info3.mBody->getType()==5 || info3.mBody->getType()==2))
								{
								Ogre::LogManager::getSingleton().getDefaultLog()->logMessage("Y2",Ogre::LML_NORMAL);
								return true;	
								}
							}

				}

				
		Ogre::LogManager::getSingleton().getDefaultLog()->logMessage("N",Ogre::LML_NORMAL);
		return false;

}

